package com.googlecode.ddplan;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertTrue;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.armedbear.lisp.Interpreter;
import org.armedbear.lisp.LispObject;
import org.jbehave.core.annotations.AfterScenario;
import org.jbehave.core.annotations.BeforeScenario;
import org.jbehave.core.annotations.Given;
import org.jbehave.core.annotations.Then;
import org.jbehave.core.annotations.When;

import com.googlecode.ddplan.testdomain.ObjWithoutName;
import com.googlecode.ddplan.testdomain.ObjWithoutType;

public class DDPlanGeneratorSteps {

	private Map<String, Object> allSymbols;

	private DDPlanGenerator planGenerator;
	private String expressionResult;
	private Exception exception;
	private ValidationResult actionValidationResult;

	public DDPlanGeneratorSteps(Map<String, Object> allSymbols) {
		this.allSymbols = allSymbols;
	}

	@BeforeScenario
	public void beforeScenario() {
		planGenerator = new DDPlanGenerator();
	}

	@AfterScenario
	public void afterScenario() {
		planGenerator = null;
		expressionResult = null;
		exception = null;
	}

	@Given("I register all these objects")
	@When("I register all these objects")
	public void register() {
		try {
			planGenerator.register(allSymbols.values());
		} catch (Exception e) {
			exception = e;
		}
	}

	@Given("I set a domain name $name")
	public void setDomainName(String name) {
		planGenerator.setDomainName(name);
	}

	@Given("a PDDL obj without an annotated name")
	public void objWithoutAnnotatedName() {
		allSymbols.put("noAnnotatedObject", new ObjWithoutName("something"));
	}

	@Given("a PDDL obj without an annotated class")
	public void objWithoutAnnotatedClass() {
		allSymbols.put("noAnnotatedClass", new ObjWithoutType("something"));
	}

	@When("I ask for the types")
	public void getTypes() {
		expressionResult = planGenerator.getTypes();
	}

	@When("I ask for the requirements")
	public void getRequirements() {
		expressionResult = planGenerator.getRequirements();
	}

	@When("I ask for the domain")
	public void getDomain() {
		expressionResult = planGenerator.getDomain();
	}

	@When("I validate the actions")
	public void validateActions() {
		actionValidationResult = planGenerator.validateActions();
	}

	@When("I ask for the predicates")
	public void getPredicates() {
		expressionResult = planGenerator.getPredicates();
	}

	@Then("The resulting expression is $result")
	public void result(String result) {
		assertThat(expressionResult, equalTo(result.replaceAll("'", "")));
	}

	@Then("I get an empty expression")
	public void result() {
		result("");
	}

	@Then("an exception in thrown with message $message")
	public void exceptionResult(String exceptionMessage) {
		assertThat(exception.getMessage(), equalTo(exceptionMessage.replaceAll("'", "")));
	}

	@Then("the resulting expression list contains $listElement")
	public void resultContains(String listElement) throws IOException {
		List<String> expressionResultElements = new ArrayList<String>();

		LispObject expressionResLisp = Interpreter.readFromString(expressionResult);
		while (expressionResLisp.length() > 0) {
			expressionResultElements.add(expressionResLisp.car().printObject());
			expressionResLisp = expressionResLisp.cdr();
		}

		assertTrue(expressionResultElements.contains(listElement.replaceAll("'", "")));
	}

	@Then("there are not any action validation error")
	public void noActionValidationErrors() {
		assertTrue(actionValidationResult.isValid());
	}
}
